package com.toutou.base.adapter

import android.annotation.SuppressLint
import android.view.ViewGroup
import androidx.databinding.Bindable
import androidx.databinding.PropertyChangeRegistry
import androidx.recyclerview.widget.RecyclerView
import com.toutou.base.BR

open class BaseRecyclerAdapter(private var normalAdapterDelegate: NormalAdapterDelegate) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>(), androidx.databinding.Observable {

    protected var list: ArrayList<Any> = initList()


    private fun initList(): ArrayList<Any> {
        return ArrayList()
    }

    @SuppressLint("NotifyDataSetChanged")
    fun clear() {
        list.clear()
//        notifyItemRangeRemoved(0, size)
        notifyDataSetChanged()////这里不能用notifyItemRange，因为会导致无数据状态不刷新 显示缺省页
        notifyChange(BR.data)
    }

    fun add(index: Int, t: Any?) {
        if (t == null) {
            return
        }

        list.add(index, t)
        notifyItemInserted(index)
        notifyChange(BR.data)
    }

    @SuppressLint("NotifyDataSetChanged")
    fun add(t: Any?) {
        
        if (t != null) {
            list.add(t)
            if (list.size < 2) {
                notifyDataSetChanged()
            } else {
                notifyItemInserted(list.size - 1)
            }
        }
        notifyChange(BR.data)
    }

    fun getPositionOfFirstObject(obj: Any?): Int {
        for (i in list.indices) {
            if (getItem(i) != null && obj != null && getItem(i)!!.javaClass == obj.javaClass) {
                return i
            }
        }
        return -1
    }

    /**
     * 移除position开始到后面的所有数据
     */
    fun clearFromPosition(position: Int) {
            while (list.size > position) {
                list.removeAt(position)
                notifyChange(BR.data)
                notifyItemRangeRemoved(position, list.size - position)
            }
    }

    fun addAll(tsList: ArrayList<*>?) {
        var ts = tsList

        if (null == ts) {
            ts = ArrayList<Any>()
        }
        if (ts.isEmpty()) return
        val forIndex = list.size
        list.addAll(ts)
        notifyChange(BR.data)
        notifyItemRangeInserted(forIndex, list.size)
    }

    fun addAll(index: Int, tsList: ArrayList<Any>?) {
        var ts = tsList

        if (null == ts) {
            ts = ArrayList<Any>()
        }
        list.addAll(index, ts)
        notifyItemRangeInserted(index, ts.size)
        notifyChange(BR.data)
    }

    fun setAll(ts: ArrayList<*>?) {
        clear()
        addAll(ts)
    }
    fun setAll(ts: List<*>?) {
        clear()
        if (!ts.isNullOrEmpty()) {
            addAll(ts.toCollection(ArrayList()))
        }
    }

    fun setAll(ts: ArrayList<*>?, limit:Int) {
        clear()
        if ((ts?.size ?: 0) > limit){
            val subList = ts?.subList(0, limit)
            addAll(subList?.toCollection(ArrayList()))
        } else{
            addAll(ts)
        }
    }

    @get:Bindable
    val data: List<*>
        get() = list


    fun remove(o: Any) {
        if (list.contains(o)) {
            val pos = list.indexOf(o)
            list.remove(o)
            notifyItemRemoved(pos)
            notifyChange(BR.data)
        }
    }

    fun removeAll(curList: ArrayList<Any>?) {
        if (curList != null && list.containsAll(curList) && curList.isNotEmpty()) {
            val pos = list.indexOf(curList[0])
            list.removeAll(curList)
            notifyItemRangeRemoved(pos, curList.size)
            notifyChange(BR.data)
        }
    }

    fun remove(position: Int) {
        if (list.size > position) {
            list.removeAt(position)
            notifyItemRemoved(position)
        }
        notifyChange(BR.data)
    }

    fun insteadObject(oldObj: Any?, newObj: Any?) {
        if (oldObj == null || newObj == null) {
            return
        }
        var position = 0
        for (i in list.indices) {
            if (getItem(i) === oldObj) {
                position = i
            }
        }
        remove(oldObj)
        list.add(position, newObj)
        notifyItemChanged(position)
        notifyChange(BR.data)
    }

    fun getItem(position: Int): Any? {
        return if (position < list.size && position > 0) {
            list[position]
        } else {
            if (list.size > 0) {
                list[0]
            } else {
                null
            }
        }
    }

    fun isFooterItem(position: Int): Boolean {
        return position >= list.size
    }

    override fun getItemViewType(position: Int): Int {
        return normalAdapterDelegate.getItemViewType(position)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return normalAdapterDelegate.onCreateViewHolder(parent, viewType)
    }


    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        normalAdapterDelegate.onBindViewHolder(
            holder,
            position
        )
    }

    override fun getItemCount(): Int {
        return  list.size
    }

    interface NormalAdapterDelegate {
        fun getItemViewType(position: Int): Int

        fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder

        fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int)
    }

    @Transient
    private var propertyChangeRegistry: PropertyChangeRegistry? = PropertyChangeRegistry()


    @Synchronized
    protected fun notifyChange(propertyId: Int) {
        if (propertyChangeRegistry == null) {
            propertyChangeRegistry = PropertyChangeRegistry()
        }
        propertyChangeRegistry!!.notifyChange(this, propertyId)
    }

    @Synchronized
    override fun addOnPropertyChangedCallback(callback: androidx.databinding.Observable.OnPropertyChangedCallback) {
        if (propertyChangeRegistry == null) {
            propertyChangeRegistry = PropertyChangeRegistry()
        }
        propertyChangeRegistry!!.add(callback)
    }

    @Synchronized
    override fun removeOnPropertyChangedCallback(callback: androidx.databinding.Observable.OnPropertyChangedCallback) {
        if (propertyChangeRegistry != null) {
            propertyChangeRegistry!!.remove(callback)
        }
    }
}